import type * as grpc from "@grpc/grpc-js";

export type CallerMethod<Request, Reply> = (
  ...args: MethodArgs<Request, Reply>
) => grpc.ClientUnaryCall;

export type MethodArgs<Request, Reply> =
  | [Request, (error?: grpc.ServiceError, result?: Reply) => void];

export type RequestOfCaller<T extends CallerMethod<any, any>> =
  T extends CallerMethod<infer R, any> ? R : never;

export type ReplyOfCaller<T extends CallerMethod<any, any>> =
  T extends CallerMethod<any, infer R> ? R : never;

export type GrpcClientMethods = {
  [name: string]: CallerMethod<any, any> | any;
};

export type GrpcClient = Record<string, CallerMethod<any, any>> & grpc.Client;

export type PromiserCaller<U extends GrpcClientMethods> = {
  [m in keyof U]: (
    request: RequestOfCaller<U[m]>
  ) => Promise<ReplyOfCaller<U[m]>>;
};
